﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Microsoft.Samples.Kinect.WpfViewers {
    public struct InputStruct {
        public byte VK;
        public byte DIK;
        public string key;
    }
    public enum Methods{
        BOTH = 0,
        DIK = 1,
        VK = 2
    };

    public static class FakeInput {
        [DllImport("user32.dll", EntryPoint = "keybd_event", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern void Keybd_event(byte vk, byte scan, int flags, int extrainfo);

        static Dictionary<string, byte> VKeys = new Dictionary<string, byte>();
        static Dictionary<string, byte> DIKeys = new Dictionary<string, byte>();

        private const int KEYDOWN = 0;
        private const int KEYUP = 2;

        public static void Init() {
            //Init our listing of keys
            InitDIK();
            InitVK();
        }

        //Sets the input structure for the proper bytes depending on what string is sent in
        public static InputStruct GetInputStruct(string Key)
        {
            Key = Key.ToUpper();
            InputStruct input = new InputStruct();
            input.key = Key;

            input.VK = VKeys[Key];
            input.DIK = DIKeys[Key];

            return input;
        }

        public static void SimulateKeyDown(InputStruct input, Methods method = Methods.BOTH)
        {
            if (Methods.BOTH == method) {
                //Virtual Keys, regular input
                Keybd_event(input.VK, 0, KEYDOWN, 0);
                //Direct Input Keys, for games using Direct Input
                Keybd_event(0, input.DIK, KEYDOWN, 0);
            } else if (Methods.DIK == method) {
                //Direct Input Keys, for games using Direct Input
                Keybd_event(0, input.DIK, KEYDOWN, 0);
            } else {
                //Virtual Keys, regular input
                Keybd_event(input.VK, 0, KEYDOWN, 0);
            }
        }

        public static void SimulateKeyUp(InputStruct input, Methods method = Methods.BOTH) {
            if (Methods.BOTH == method) {
                //Virtual Keys, regular input
                Keybd_event(input.VK, 0, KEYUP, 0);
                //Direct Input Keys, for games using Direct Input
                Keybd_event(0, input.DIK, KEYUP, 0);
            } else if (Methods.DIK == method) {
                //Direct Input Keys, for games using Direct Input
                Keybd_event(0, input.DIK, KEYUP, 0);
            } else {
                //Virtual Keys, regular input
                Keybd_event(input.VK, 0, KEYUP, 0);
            }
        }

        public static void InitVK() {
            //http://delphi.about.com/od/objectpascalide/l/blvkc.htm
            //Add A-Z + some misc keys
            for (int i = 65; i < (65 + 32); i++) {
                VKeys.Add(((char)i).ToString(), (byte)i);
            }
            //Add 0-9
            for (int i = 30; i < 40; i++) {
                VKeys.Add(i.ToString(), (byte)(i - 30));
            }

            //Application keys
            VKeys.Add("LSHIFT", 0xA0);
            VKeys.Add("RSHIFT", 0xA1);
            VKeys.Add("LCONTROL", 0xA2);
            VKeys.Add("RCONTROL", 0xA3);
            VKeys.Add("SPACE", 0x20);
            VKeys.Add("TAB", 0x09);


            //Arrows
            VKeys.Add("UP", 0x26);
            VKeys.Add("DOWN", 0x28);
            VKeys.Add("LEFT", 0x25);
            VKeys.Add("RIGHT", 0x27);
            VKeys.Add("INSERT", 0x2D);
            VKeys.Add("DELETE", 0x2E);
            VKeys.Add("HOME", 0x24);
            VKeys.Add("END", 0x23);
            VKeys.Add("PGUP", 0x21);
            VKeys.Add("PGDN", 0x22);
        }

        public static void InitDIK() {
            //Top Row numbers 0-9
            DIKeys.Add("0", 0x08);
            DIKeys.Add("1", 0x02);
            DIKeys.Add("2", 0x03);
            DIKeys.Add("3", 0x04);
            DIKeys.Add("4", 0x05);
            DIKeys.Add("5", 0x06);
            DIKeys.Add("6", 0x07);
            DIKeys.Add("7", 0x08);
            DIKeys.Add("8", 0x09);
            DIKeys.Add("9", 0x0A);

            //Alpha A-Z
            DIKeys.Add("A", 0x1E);
            DIKeys.Add("B", 0x30);
            DIKeys.Add("C", 0x2E);
            DIKeys.Add("D", 0x20);
            DIKeys.Add("E", 0x12);
            DIKeys.Add("F", 0x21);
            DIKeys.Add("G", 0x22);
            DIKeys.Add("H", 0x23);
            DIKeys.Add("I", 0x17);
            DIKeys.Add("J", 0x24);
            DIKeys.Add("K", 0x25);
            DIKeys.Add("L", 0x26);
            DIKeys.Add("M", 0x32);
            DIKeys.Add("N", 0x31);
            DIKeys.Add("O", 0x18);
            DIKeys.Add("P", 0x19);
            DIKeys.Add("Q", 0x10);
            DIKeys.Add("R", 0x13);
            DIKeys.Add("S", 0x1F);
            DIKeys.Add("T", 0x14);
            DIKeys.Add("U", 0x16);
            DIKeys.Add("V", 0x2F);
            DIKeys.Add("W", 0x11);
            DIKeys.Add("X", 0x2D);
            DIKeys.Add("Y", 0x15);
            DIKeys.Add("Z", 0x2C);


            //Application keys
            DIKeys.Add("LSHIFT", 0x2A);
            DIKeys.Add("RSHIFT", 0x36);
            DIKeys.Add("LCONTROL", 0x1D);
            DIKeys.Add("RCONTROL", 0x9D);
            DIKeys.Add("SPACE", 0x39);
            DIKeys.Add("TAB", 0x0F);

            
            //Arrows
            DIKeys.Add("UP", 0xC8);
            DIKeys.Add("DOWN", 0xD0);
            DIKeys.Add("LEFT", 0xCB);
            DIKeys.Add("RIGHT", 0xCD);
            DIKeys.Add("INSERT", 0xD2);
            DIKeys.Add("DELETE", 0xD3);
            DIKeys.Add("HOME", 0xC7);
            DIKeys.Add("END", 0xCF);
            DIKeys.Add("PGUP", 0xC9);
            DIKeys.Add("PGDN", 0xD1);

        }
    }
}
